﻿using BunnyEater.Domain.Base;
using BunnyEater.Domain.SystemManagement;
using BunnyEater.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace BunnyEater.Repository.BaseRepository
{
    /// <summary>
    /// 通用仓储基类，提供基础的CRUD操作
    /// </summary>
    /// <typeparam name="TEntity">实体类型，必须继承自BaseEntity</typeparam>
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
    {
        #region 注册上下文对象

        /// <summary>
        /// 数据库上下文对象，用于访问数据库
        /// 使用readonly 确保在构造函数初始化后不能再被修改
        /// </summary>
        private readonly BunnyEaterContext _bunnyEaterContext;
        /// <summary>
        /// 泛型实体集合，表示数据库对应的表
        /// DbSet<TEntity> 用于特定实体类型的数据库操作（CRUD）
        /// </summary>
        private readonly DbSet<TEntity> _dbSet;

        /// <summary>
        /// HTTP上下文访问器，用于获取当前用户信息
        /// </summary>
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger<Repository<TEntity>> _logger;


        /// <summary>
        /// 仓储类构造函数
        /// </summary>
        /// <param name="bunnyEaterContext">数据库上下文实例，由依赖注入框架提供</param>
        /// <param name="httpContextAccessor">HTTP上下文访问器</param>
        /// <param name="logger">日志记录器</param>
        public Repository(BunnyEaterContext bunnyEaterContext
            , IHttpContextAccessor httpContextAccessor
            , ILogger<Repository<TEntity>> logger
            )
        {
            _bunnyEaterContext = bunnyEaterContext;
            _dbSet = _bunnyEaterContext.Set<TEntity>();
            _httpContextAccessor = httpContextAccessor;
            _logger = logger;
        }

        #endregion


        #region 仓储基类方法实现

        /// <summary>
        /// 登录查询
        /// </summary>
        /// <param name="account">账号</param>
        /// <returns></returns>
        public async Task<User?> GetUserForLoginAsync(string? account)
        {
            return await _bunnyEaterContext.Set<User>().FirstOrDefaultAsync(x => x.Account == account);
        }



        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<bool> GetEntityAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await _dbSet.AnyAsync(predicate);
        }


        /// <summary>
        /// 获取所有的数据集合
        /// </summary>
        /// <returns>返回数据集合</returns>
        public async Task<List<TEntity>> GetAllListAsync()
        {
            return await _dbSet.ToListAsync();
        }




        /// <summary>
        /// 查询数据集合
        /// </summary>
        /// <returns>返回数据集合</returns>
        public IQueryable<TEntity> GetListQuery()
        {
            return _dbSet.AsQueryable();
        }

        /// <summary>
        /// 根据数据对象主键查询单条数据
        /// </summary>
        /// <param name="key">数据对象主键</param>
        /// <returns>返回单条数据对象</returns>
        public async Task<TEntity> GetEntityByIdAsync(KeyEntity key)
        {
            var entity = await _dbSet.FindAsync(key.Id).ConfigureAwait(false);
            return entity;
        }

        /// <summary>
        /// 获取数据集合的总记录数
        /// </summary>
        /// <returns>返回数据集合的总记录数</returns>
        public int GetTotalCount()
        {
            return _dbSet.Count();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex">页码（从1开始）</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="predicate">查询条件</param>
        /// <param name="orderBy">排序表达式</param>
        /// <param name="isAscending">是否升序</param>
        /// <returns>分页结果</returns>
        public async Task<Page<TEntity>> GetPagedListAsync(int pageIndex, int pageSize,
            Expression<Func<TEntity, bool>>? predicate = null,
            Expression<Func<TEntity, object>>? orderBy = null,
            bool isAscending = true)
        {
            // 参数验证
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;

            // 构建查询
            IQueryable<TEntity> query = _dbSet.AsQueryable();

            // 应用查询条件
            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            // 获取总记录数
            int totalItems = await query.CountAsync();

            // 应用排序
            if (orderBy != null)
            {
                query = isAscending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy);
            }
            else
            {
                // 默认按Id排序
                query = query.OrderBy(x => x.Id);
            }

            // 应用分页
            var items = await query
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();

            // 计算总页数
            int totalPages = (int)Math.Ceiling((double)totalItems / pageSize);

            // 返回分页结果
            return new Page<TEntity>
            {
                Items = items,
                PageNumber = pageIndex,
                PageSize = pageSize,
                TotalPages = totalPages,
                TotalItems = totalItems
            };
        }

        /// <summary>
        /// 分页查询（支持复杂排序）
        /// </summary>
        /// <param name="pageIndex">页码（从1开始）</param>
        /// <param name="pageSize">每页大小</param>
        /// <param name="predicate">查询条件</param>
        /// <param name="orderBy">排序表达式</param>
        /// <returns>分页结果</returns>
        public async Task<Page<TEntity>> GetPagedListAsync(int pageIndex, int pageSize,
            Expression<Func<TEntity, bool>>? predicate = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null)
        {
            // 参数验证
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;

            // 构建查询
            IQueryable<TEntity> query = _dbSet.AsQueryable();

            // 应用查询条件
            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            // 获取总记录数
            int totalItems = await query.CountAsync();

            // 应用排序
            if (orderBy != null)
            {
                query = orderBy(query);
            }
            else
            {
                // 默认按Id排序
                query = query.OrderBy(x => x.Id);
            }

            // 应用分页
            var items = await query
                .Skip((pageIndex - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();

            // 计算总页数
            int totalPages = (int)Math.Ceiling((double)totalItems / pageSize);

            // 返回分页结果
            return new Page<TEntity>
            {
                Items = items,
                PageNumber = pageIndex,
                PageSize = pageSize,
                TotalPages = totalPages,
                TotalItems = totalItems
            };
        }

        /// <summary>
        /// 新增单条数据
        /// </summary>
        /// <param name="entity">需要新增的数据对象</param>
        /// <returns>返回新增数据的受影响行数</returns>
        public async Task<int> InsertEntityAsync(TEntity entity)
        {
            string creatorId = GetUserId();

            // 如果Id为空，赋值Guid字符串
            var idProp = entity.GetType().GetProperty("Id");
            if (idProp != null && (idProp.GetValue(entity) == null || string.IsNullOrEmpty(idProp.GetValue(entity)?.ToString())))
            {
                idProp.SetValue(entity, Guid.NewGuid().ToString());
            }

            SetCreator(entity, creatorId, null);
            _dbSet.Add(entity);
            return await _bunnyEaterContext.SaveChangesAsync();
        }

        /// <summary>
        /// 批量新增数据集合
        /// </summary>
        /// <param name="entities">需要新增的数据集合</param>
        /// <returns>返回新增数据的受影响行数</returns>
        public async Task<int> InsertEntityAsync(IEnumerable<TEntity> entities)
        {
            string creatorId = GetUserId();
            if (creatorId == string.Empty) return -1;
            if (entities == null) return default;

            var entityList = entities.ToList();
            if (!entityList.Any()) return default;

            foreach (var entity in entityList)
            {
                // 如果Id为空，赋值Guid字符串
                var idProp = entity.GetType().GetProperty("Id");
                if (idProp != null && (idProp.GetValue(entity) == null || string.IsNullOrEmpty(idProp.GetValue(entity)?.ToString())))
                {
                    idProp.SetValue(entity, Guid.NewGuid().ToString());
                }
                SetCreator(entity, creatorId, null);
            }
            await _dbSet.AddRangeAsync(entities).ConfigureAwait(false);
            return await _bunnyEaterContext.SaveChangesAsync().ConfigureAwait(false);
        }

        /// <summary>
        /// 更新数据对象
        /// </summary>
        /// <param name="entity">需要更新的数据对象</param>
        /// <returns>返回更新数据的受影响行数</returns>
        public async Task<int> UpdateEntityAsync(TEntity entity)
        {
            string modifierId = GetUserId();
            if (modifierId == string.Empty) return -1;
            SetModifier(entity, modifierId, null);
            _dbSet.Entry(entity).State = EntityState.Modified;
            return await _bunnyEaterContext.SaveChangesAsync();

        }

        /// <summary>
        /// 根据数据对象主键软删除数据对象
        /// </summary>
        /// <param name="key">需要软删除的数据对象主键</param>
        /// <returns>返回软删除数据的受影响行数</returns>
        public async Task<int> DeleteByIdAsync(KeyEntity key)
        {
            string deleterId = GetUserId();
            if (deleterId == string.Empty) return -1;
            var entity = await GetEntityByIdAsync(key);
            if (entity != null)
            {
                SetDeleter(entity, deleterId, null);
                _dbSet.Entry(entity).State = EntityState.Modified;
                return await _bunnyEaterContext.SaveChangesAsync();
            }
            return default;
        }

        /// <summary>
        /// 根据数据对象主键真删除数据对象
        /// </summary>
        /// <param name="key">数据对象主键</param>
        /// <returns>返回删除数据的受影响行数</returns>
        public async Task<int> DeleteEntityAsync(KeyEntity key)
        {
            var entity = await GetEntityByIdAsync(key);
            if (entity != null)
            {
                //真删除
                _dbSet.Entry(entity).State = EntityState.Deleted;
                return await _bunnyEaterContext.SaveChangesAsync();
            }
            return default;
        }

        /// <summary>
        /// 批量软删除数据对象
        /// </summary>
        /// <param name="ids">需要删除的数据对象Id集合</param>
        /// <returns>返回软删除数据的受影响行数</returns>
        public async Task<int> BulkDeleteAsync(IEnumerable<Guid> ids)
        {
            string deleterId = GetUserId();
            if (deleterId == string.Empty) return -1;
            return await _dbSet
                .Where(x => ids.Contains(EF.Property<Guid>(x, "Id")))
                .ExecuteUpdateAsync(setter => setter
                .SetProperty(e => e.IsDelete, true));
            //.SetProperty(e => e.DeleteTime, DateTime.Now)
            //.SetProperty(e => e.DeleterId, deleterId))

        }
        /// <summary>
        /// 执行SQL语句
        /// </summary>
        /// <param name="sqlStr">需要执行的SQL语句</param>
        /// <returns>返回受影响行数</returns>
        public int ExecuteSQL(string sqlStr)
        {
            return _bunnyEaterContext.Database.ExecuteSqlRaw(sqlStr);
        }


        /// <summary>
        /// 使用SQL脚本查询
        /// </summary>
        /// <param name="sqlStr">需要执行的SQL脚本</param>
        /// <param name="parameters">SQL脚本所需要的参数</param>
        /// <returns></returns>
        public IQueryable<TEntity> FromSQL(string sqlStr, IEnumerable<object> parameters)
        {
            return !parameters.Any() ? _dbSet.FromSqlRaw(sqlStr) : _dbSet.FromSqlRaw(sqlStr, parameters);
        }

        /// <summary>
        /// 更新单个字段
        /// </summary>
        /// <param name="key">实体的主键</param>
        /// <param name="propertyName">要更新的字段名称</param>
        /// <param name="value">新的字段值</param>
        /// <returns>返回更新操作的受影响行数</returns>
        public async Task<int> UpdateFieldAsync(KeyEntity key, string propertyName, object value)
        {
            string modifierId = GetUserId();
            if (modifierId == string.Empty) return -1;

            var entity = await GetEntityByIdAsync(key);
            if (entity == null)
            {
                _logger.LogError($"实体未找到，主键为：{key.Id}");
                return 0;
            }

            // 设置修改人信息
            SetModifier(entity, modifierId, null);

            // 使用 Entry 方法更新指定字段
            _bunnyEaterContext.Entry(entity).Property(propertyName).CurrentValue = value;

            return await _bunnyEaterContext.SaveChangesAsync();


        }

        #endregion

        #region 设置审计字段

        /// <summary>
        /// 设置创建人信息
        /// </summary>
        /// <param name="entity">要设置创建人信息的实体对象</param>
        /// <param name="userId">创建人Id</param>
        /// <param name="customTime">用于测试的创建时间</param>
        private void SetCreator(TEntity entity, string userId, DateTime? customTime)
        {
            if (entity is BaseEntity baseEntity)
            {
                baseEntity.CreatorId = userId.ToString();
                baseEntity.CreateTime = customTime ?? DateTime.Now;
            }
        }

        /// <summary>
        /// 设置修改人信息
        /// </summary>
        /// <param name="entity">要设置修改人信息的实体对象</param>
        /// <param name="userId">修改人Id</param>
        /// <param name="customTime">用于测试的修改时间</param>
        private void SetModifier(TEntity entity, string userId, DateTime? customTime)
        {
            if (entity is BaseEntity baseEntity)
            {
                baseEntity.ModifierId = userId.ToString();
                baseEntity.ModifyTime = customTime ?? DateTime.Now;
            }
        }

        /// <summary>
        /// 设置删除人信息
        /// </summary>
        /// <param name="entity">要设置删除人信息的实体对象</param>
        /// <param name="userId">删除人Id</param>
        /// <param name="customTime">用于测试的删除时间</param>
        private void SetDeleter(TEntity entity, string userId, DateTime? customTime)
        {
            if (entity is BaseEntity baseEntity)
            {
                //baseEntity.DeleterId = userId;
                //baseEntity.DeleteTime = customTime ?? DateTime.Now;
                baseEntity.IsDelete = true;
            }
        }

        /// <summary>
        /// 获取当前登录用户信息
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private /*Guid*/ string GetUserId()
        {

            //从httpcontext中获取jwt认证登录信息
            var NameIdentifier = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            var Name = _httpContextAccessor.HttpContext?.User.FindFirst(ClaimTypes.Name)?.Value;
            //取出已登录的用户Id和账号名称
            var account = _httpContextAccessor.HttpContext?.User.FindFirst("account")?.Value;
            var userIdClaim = _httpContextAccessor.HttpContext?.User.FindFirst("userId")?.Value;
            //过期时间
            var exp = _httpContextAccessor.HttpContext?.User.FindFirst(JwtRegisteredClaimNames.Exp)?.Value;

            if (userIdClaim == null || string.IsNullOrEmpty(userIdClaim))
            {
                _logger.LogError("无法获取有效的用户标识");
                return string.Empty; // 返回null表示未获取到有效的用户标识
            }

            return userIdClaim; // 直接返回userIdClaim作为用户标识
        }

        #endregion
    }
}
